﻿/// <reference path="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2-vsdoc.js"/>

var Microsoft = window.Microsoft || {};
Microsoft.Support = Microsoft.Support || {};
Microsoft.Support.GSS = Microsoft.Support.GSS || {};

Microsoft.Support.GSS.Slider = function (selector, args) {
    var _this = this;
    var _$this = $(this);
    var _$ct = $(selector);
    var _defaultOptions = {
        width: 0,
        autoHeight: true,
        initPageIndex: 0,
        pagesSelector: $('> div', _$ct),
        easingEffect: 'swing',
        isRTL: false
    };
    var _opts = $.extend({}, _defaultOptions, args);

    var _$pagesWrapper = $("<div></div>");
    var _pages = [];

    var _currPageIdx = 0;
    var _$currPage = $();

    var _setHeight = function (height) {
        _$ct.height(height);
        _$pagesWrapper.height(height);
    };

    var _stopAnimation = function () {
        while (_$pagesWrapper.is(":animated")) {
            _$pagesWrapper.stop(false, true);
        }
    };

    var _gotoPage = function (idx, useAnimation, triggerEvent, callback, continuePrevAnimation) {
        var page = _pages[idx];
        if (page === undefined || page === null) {
            return false;
        }

        if (page !== _$currPage[0] || idx !== _currPageIdx) {
            var $page = $(page);
            var evtParams = {
                fromPage: _$currPage,
                fromPageIndex: _currPageIdx,
                toPage: $page,
                toPageIndex: idx,
                cancel: false
            };
            if (triggerEvent !== false) {
                _$this.trigger("beforepagechange", [evtParams]);
            }
            if (evtParams.cancel !== true) {
                if (continuePrevAnimation !== true) {
                    _stopAnimation();
                }

                $(_pages).show();
                _$pagesWrapper.width(_opts.width * _pages.length).animate(_opts.isRTL ? { right: -(_currPageIdx * _opts.width) } : { left: -(_currPageIdx * _opts.width) }, 0);

                _currPageIdx = idx;
                _$currPage = $page;

                if (_opts.autoHeight) {
                    evtParams.toPage.height('auto');

                    // we need set source page height to target page height if former height is larger for avoiding page leaping(bad UX)
                    var srcHeight = evtParams.fromPage.height();
                    var targetHeight = evtParams.toPage.height();
                    if (srcHeight > targetHeight) {
                        evtParams.fromPage.height(targetHeight);
                    }
                }


                _$pagesWrapper.animate(
                    _opts.isRTL ? { right: -idx * _opts.width } : { left: -idx * _opts.width },
                    useAnimation ? 1000 : 0,
                    _opts.easingEffect,
                    function () {

                        if (triggerEvent === true) {
                            _$this.trigger("pagechange", [idx, $page]);
                        }

                        $(_pages).not($page).hide();
                        _$pagesWrapper.animate(_opts.isRTL ? { right: 0 } : { left: 0 }, 0);

                        if ($.isFunction(callback)) {
                            callback();
                        }
                    }
                );
            }
        } else {
            if ($.isFunction(callback)) {
                callback();
            }
        }
    };

    var _insertPage = function (page, pos) {
        var $page = $(page);
        pos = (pos = parseInt(pos, 10)) >= 0 ? pos : _pages.length;

        // find existing page in pages, and remove it, avoiding to insert page in list repeatly.
        $.each(_pages, function (idx, p) {
            if (p === page) {
                _pages.splice(idx, 1);  // remove it from its original position
                return false;
            }
        });

        var prevPage = _pages[pos - 1];
        $page.detach();
        $page.find("script").remove();  // BUG FIX: we should remove all script tags in $page html, otherwise script will be executed again when insert back into page.
        $page.width(_opts.width).css({
            minHeight: '1px',
            float: _opts.floatDirection
        }).hide();

        if (prevPage) {
            $(prevPage).after(page);
            _pages.splice(pos, 0, page);
        } else if (pos <= 0) {
            _$pagesWrapper.prepend(page);
            _pages.splice(0, 0, page);
        } else {
            _$pagesWrapper.append(page);
            _pages.push(page);
        }
    };

    var _removePage = function (page, detachOnly) {
        for (var i = 0; i < _pages.length; i++) {
            if (_pages[i] === page) {
                if (detachOnly === true) {
                    $(page).detach();
                } else {
                    $(page).remove();
                }
                _pages.splice(i, 1);
                break;
            }
        }
    };

    var _init = function () {
        // set width
        if (_opts.width > 0) {
            _$ct.width(_opts.width);
        } else {
            _opts.width = _$ct.width();
        }

        _opts.floatDirection = "left";
        if (_opts.isRTL) {
            _opts.floatDirection = "right";
        }

        _opts.autoHeight = _opts.autoHeight === true;
        if (!_opts.autoHeight) {
            _opts.height = parseInt(_opts.height, 10);
            if (_opts.height > 0) {
                _setHeight(_opts.height);
            }
        }
        _opts.height = parseInt(_opts.height, 10);
        if (_opts.autoHeight || !(_opts.height > 0)) {
            _opts.height = 0;
        }

        var $pages = $(_opts.pagesSelector).detach();
        _$ct.empty().append(_$pagesWrapper).css({
            overflow: 'hidden',
            position: 'relative'
        });
        $pages.each(function () {
            _insertPage(this);
        });
        _$pagesWrapper.css({
            position: 'relative'
        });

        // init current page
        var idx = parseInt(_opts.initPageIndex, 10);
        if (!(idx >= 0 && idx < _pages.length)) {
            idx = 0;
        }
        _gotoPage(idx, false, false);
    };

    _init();

    _this.getPageIndex = function () {
        return _currPageIdx;
    };

    _this.getPage = function (idx) {
        if (idx === undefined) {
            idx = _currPageIdx;
        } else {
            idx = parseInt(idx, 10);
        }

        if (idx >= 0 && idx < _pages.length) {
            return _pages[idx];
        } else {
            return null;
        }
    }

    _this.resetCurrPageHeight = function () {
        if (!_opts.autoHeight) {
            _setHeight(_$currPage.height());
        }
    };

    _this.gotoPage = function (idx, animate, callback) {
        idx = parseInt(idx, 10);
        if (idx >= 0 && idx < _pages.length) {
            _gotoPage(idx, animate !== false, true, callback);
        }
    };

    _this.insertPage = function (page, idx) {
        _insertPage(page, idx);
    };

    _this.replacePage = function (idx, page, callback, detachRemovedPage) {
        idx = (idx = parseInt(idx, 10)) >= 0 ? idx : _currPageIdx;
        _stopAnimation(); // stop animation if previous transition hasn't completed yet.
        if (_pages[idx] === page || page === null || page === undefined) {
            _gotoPage(idx, true, true, callback);
            return;
        }

        //TODO: when the param[page] is existing in pages, and specific another position, that will cause issue!
        if (_currPageIdx === idx) {
            _insertPage(page, idx + 1);
            _gotoPage(idx + 1, true, false, function () {
                var removedPage = _pages[idx];
                _removePage(removedPage, detachRemovedPage === true);
                _gotoPage(idx, false, true, function () {
                    if ($.isFunction(callback)) {
                        callback(removedPage);
                    }
                },
                true);  //set continue previous animation to true for making _gotoPage avoid to execute _stopAnimation again. if false, that will cause unexpected issue!!!
            });
        } else {
            var removedPage = _pages[idx];
            _removePage(removedPage, detachRemovedPage === true);
            _insertPage(page, idx);
            if ($.isFunction(callback)) {
                callback(removedPage);
            }
        }
    };

    _this.prevPage = function (repeat, callback) {
        var idx = _currPageIdx - 1;
        if (idx < 0) {
            idx = repeat === true ? _pages.length - 1 : 0;
        }
        _gotoPage(idx, true, true, callback);
    };

    _this.nextPage = function (repeat, callback) {
        var idx = _currPageIdx + 1;
        if (idx >= _pages.length) {
            idx = repeat === true ? 0 : _pages.length - 1;
        }
        _gotoPage(idx, true, true, callback);
    };
};